package com.ly.mp.busicen.rule.flow.action.plugin;

import static com.ly.mp.busicen.rule.XruleStrUtils.splitXKH;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.StringUtils;

import com.ly.mp.busicen.common.context.BusicenException;
import com.ly.mp.busicen.common.context.EntityResult;
import com.ly.mp.busicen.common.context.OptResult;
import com.ly.mp.busicen.rule.flow.FlowSpelUtil;
import com.ly.mp.busicen.rule.flow.IDataVolume;
import com.ly.mp.busicen.rule.flow.action.ActionException;
import com.ly.mp.busicen.rule.flow.action.ActionExecuteBase;
import com.ly.mp.busicen.rule.flow.action.ActionResult;
import com.ly.mp.busicen.rule.flow.action.IAction;
import com.ly.mp.busicen.rule.flow.action.IActionResult;
import com.ly.mp.busicen.rule.flow.action.IActionResult.Signal;

public class ActionExecuteSpBean extends ActionExecuteBase
		implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {

	Logger log = LoggerFactory.getLogger(ActionExecuteSpBean.class);

	ApplicationContext context;

	Map<String, Object> app = new HashMap<String, Object>();

	@Override
	public IActionResult execute(IAction action, IDataVolume dataVolume) {
		ActionResult result = ActionResult.create();
		result.signal(Signal.CONTINUE);
		result.action(action.action());
		result.msg(action.msg());
		StandardEvaluationContext sec = (StandardEvaluationContext) action.extention().get(IAction.EXTKEY_SPEL);
		try {			
			sec.setVariable("app", app);
			try {
				String param = splitXKH(action.content());
				if (StringUtils.isEmpty(param)) {
					throw new ActionException("SPBEAN执行内容为空");
				}
				Object data = FlowSpelUtil.spelGetData(action, param);
				if (data == null) {
					throw new ActionException("SPBEAN返回结果为空");
				}
				
				if (data instanceof EntityResult) {
					EntityResult<?> dataResult = (EntityResult<?>) data;
					if (!"1".equals(dataResult.getResult())) {
						log.info("SPBEAN调用正常，但结果状态为失败，执行结果状态为中断。。");
						result.signal(Signal.BREAK);
						result.msg(dataResult.getMsg());
						result.setConvertMsg(false);
						return result;
					}
					result.data(dataResult.getRows());
					dataVolume.ext().put(action.action(), dataResult.getRows());
				}else if (data instanceof OptResult) {
					OptResult dataResult = (OptResult) data;
					if (!"1".equals(dataResult.getResult())) {
						log.info("SPBEAN调用正常，但结果状态为失败，执行结果状态为中断。。");
						result.signal(Signal.BREAK);
						result.msg(dataResult.getMsg());
						result.setConvertMsg(false);
						return result;
					}
				}else {
					String errormsg = String.format("SPBEAN返回结果类型为%s,非EntityResult或OptResult", data.getClass().getSimpleName()); 
					throw new ActionException(errormsg);
				}
				
			} catch (SpelEvaluationException e) {
				if (e.getCause() != null && e.getCause() instanceof InvocationTargetException) {
					InvocationTargetException ie = (InvocationTargetException) e.getCause();
					if (ie.getTargetException() != null && ie.getTargetException() instanceof BusicenException) {
						throw (BusicenException) ie.getTargetException();
					}
				}
				throw e;
			}
			result.nextAction(defaultNextActionCode(action, null));
		}catch (BusicenException e) {
			log.info("SPBEAN调用异常，执行结果状态为中断。。");
			result.signal(Signal.BREAK);
			result.msg(e.getMessage());
			result.setConvertMsg(false);
			return result;
		}catch (Exception e) {
			result.signal(Signal.EXCPT);
			result.excpt(e);
		} finally {
			sec.setVariable("app", null);
		}
		return result;
	}

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		String[] beanNames = event.getApplicationContext().getBeanDefinitionNames();
		Map<String, Object> beans = new HashMap<String, Object>();
		for (String name : beanNames) {
			Object bean = event.getApplicationContext().getBean(name);
			beans.put(name, bean);
		}
		app = beans;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		context = applicationContext;
	}

}
